package io.oschina.binv.kapp.framework

import android.Manifest
import android.annotation.TargetApi
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.support.v4.app.Fragment
import android.support.v7.app.AlertDialog
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.trello.rxlifecycle2.RxLifecycle
import com.trello.rxlifecycle2.android.FragmentEvent
import com.trello.rxlifecycle2.components.support.RxFragment
import io.oschina.binv.kapp.BuildConfig
import io.oschina.binv.kapp.framework.extend.printOrReport
import io.oschina.binv.kapp.framework.utils.Logger
import io.reactivex.ObservableTransformer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import kotlin.properties.Delegates


/**
 * Created by xuybin on 2017/8/22.
 */
abstract class BaseFragment :RxFragment() {
    val Log= Logger(this::class.java.canonicalName)
    val contentView by lazy {
        view!!
    }
    fun <T : View> findViewById(id:Int): T {
      return  contentView.findViewById<T>(id)
    }

    companion object {
        inline  fun<reified F : Fragment> newInstance(args:Bundle): F {
            val constr = F::class.java.getConstructor();
            val fragment = constr.newInstance();
            fragment.arguments=args
            return fragment
        }
    }
    fun finishEventFor(fragmentName:String): BaseActivity.Companion.FinishEvent {
       return BaseActivity.Companion.FinishEvent(activity::class.java.canonicalName,fragmentName)
    }
    fun <T> ioToMain(): ObservableTransformer<T, T> {
        return ObservableTransformer { upstream ->
            upstream.compose(RxLifecycle.bindUntilEvent(lifecycle(), FragmentEvent.DESTROY)).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
        }
    }

    /**********以下重新定义********/
    /*
     * * 把不属于强制生命周期的onRestoreInstanceState和onSaveInstanceState转换为强制生命周期
     * * 外部传递的参数或内部运行中产生的状态.返回函数用于保存
     */
    abstract fun setContentView(inflater: LayoutInflater,container: ViewGroup?):View
    abstract fun initViewsAndLocalData(savedBundle:Bundle):(outBundle:Bundle)->Unit
    abstract fun loadRemoteData()
    /********** 以上重新定义********/

    var saveArgsOrStatus by Delegates.notNull<(outBundle:Bundle)->Unit>()
    private var isViewActive =false
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        Log.i("onCreateView")
       try {
           return setContentView(inflater,container)
       }catch (ex :Throwable){
           context.printOrReport(ex)
       }
        return  super.onCreateView(inflater, container, savedInstanceState)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        Log.i("onViewCreated")
        isViewActive=true
        try {
            if (arguments == null) arguments=Bundle()
            saveArgsOrStatus=initViewsAndLocalData(arguments)
            loadRemoteData()
        }catch (ex:Throwable){
            context.printOrReport(ex)
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        Log.i("onSaveInstanceState")
        try {
            if (arguments == null) arguments=Bundle()
            saveArgsOrStatus(arguments)//只保存arguments传递过来的值被修改后,覆盖原值
        }catch (ex:Throwable){
            context.printOrReport(ex)
        }
        super.onSaveInstanceState(outState)
    }

    override fun onAttach(context: Context?) {
        Log.i("onAttach")
        super.onAttach(context)
    }

    override fun onStart() {
        Log.i("onStart")
        super.onStart()
    }

    override fun onResume() {
        Log.i("onResume")
        super.onResume()
    }

    override fun onPause() {
        Log.i("onPause")
        super.onPause()
    }

    override fun onStop() {
        Log.i("onStop")
        super.onStop()
    }

    override fun onDestroyView() {
        Log.i("onDestroyView")
        //Log.e("view1="+view)
        super.onDestroyView()
        //Log.e("view2="+view)
        isViewActive =false
    }

    override fun onDestroy() {
        Log.i("onDestroy")
        super.onDestroy()
    }

    override fun onDetach() {
        Log.i("onDetach")
        super.onDetach()
    }
    //data一定声明为Intent?,而不能是Intent否则,直接结束,未调用setResult,会调用了setResult但未给Intent时都会崩溃
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        Log.i("onActivityResult")
        super.onActivityResult(requestCode, resultCode, data)
    }
    /**********以下辅助函数********/
    fun isViewActiveRunNow(run:()->Unit){
        //if(view!=null){ onDestroyView后的值未验证
        if(isViewActive){
            run()
        }
    }

    fun isViewShowRunNow(run:()->Unit){
        run()
    }

    fun isViewHidRunNow(run:()->Unit){
        run()
    }
    private class BeforeFinish(val run: () -> Unit)
    private val beforeFinishRuns= mutableListOf<BeforeFinish>()
    fun beforeFinishRunAsync(run:()->Unit){
        beforeFinishRuns.add(BeforeFinish(run))
    }
    var beforeFinishing=false //防止多次点击

    //不能有阻塞调用，否则导致退出不了;内部不能有finish调用会造成死循环
    //只能配对使用，才能达到效果
    //Fragments.beforeFinishRunAsync->Fragments.finish()
    //Activity.beforeFinishRunAsync->Activity.finish()
    fun finish(fromParent:Boolean=false){
        if (beforeFinishing){
            return
        }
        beforeFinishing=true
        try{
            beforeFinishRuns.forEach { b->b.run() }
            val  fragments= childFragmentManager.fragments
            if (fragments!=null ){
                fragments.forEach { fragment->
                    if(fragment is BaseFragment){
                        fragment.finish(true)
                    }
                }
            }
        }catch (ex:Throwable){
            context.printOrReport(ex)
        }
        //不加判断也会死循环
        if(!fromParent){
            activity.finish()
        }
    }

    /**********以下异步请求授权,并执行相关内容********/
    private class RequestPermission(val permissions: Array<String>
                                    , val hasDeniedPermissions: Array<String>
                                    , val onPermissionsDenied: (deniedPermissions: Array<String>, isShowRequestPermissionRationale: Boolean) -> Unit
                                    , val onPermissionsGranted: () -> Unit) {
        /** 只要文件的路径相同，就认为是相同的文件  */
        override fun equals(o: Any?): Boolean {
            try {
                val other = o as RequestPermission
                return this.permissions == other.permissions && this.onPermissionsGranted == other.onPermissionsGranted
            } catch (ex: Exception) {
                ex.printStackTrace()
            }
            return super.equals(o)
        }

        companion object {
            fun permissionsDesc(permissions: Array<String>): Array<String> {
                val permissionsDescSet = mutableSetOf<String>()
                permissions.forEach { p ->
                    when (p) {
                        Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE -> permissionsDescSet.add("存储卡")
                        Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR -> permissionsDescSet.add("日历")
                        Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS, Manifest.permission.GET_ACCOUNTS -> permissionsDescSet.add("联系人")
                        Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION -> permissionsDescSet.add("位置")
                        Manifest.permission.RECORD_AUDIO -> permissionsDescSet.add("麦克风")
                        Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE, Manifest.permission.READ_CALL_LOG, Manifest.permission.WRITE_CALL_LOG
                            , Manifest.permission.ADD_VOICEMAIL, Manifest.permission.USE_SIP, Manifest.permission.PROCESS_OUTGOING_CALLS -> permissionsDescSet.add("电话")
                        Manifest.permission.BODY_SENSORS -> permissionsDescSet.add("传感器")
                        Manifest.permission.SEND_SMS, Manifest.permission.RECEIVE_SMS, Manifest.permission.READ_SMS, Manifest.permission.RECEIVE_WAP_PUSH,
                        Manifest.permission.RECEIVE_MMS -> permissionsDescSet.add("短信")
                        Manifest.permission.CAMERA -> permissionsDescSet.add("摄像头")
                    }
                }
                return permissionsDescSet.toTypedArray()
            }
        }
    }

    private val requestPermissionMap = mutableMapOf<Int, RequestPermission>()
    private var permissionRequestCode = 23100

    private fun topFragmentRequestPermissions(fragment:Fragment,needPermissions:Array<String>,requestCode:Int){
        //子Fragment中使用requestPermissions方法,onRequestPermissionsResult不会回调回来,必须顶级topFragment.RequestPermissions
        if(fragment.parentFragment!=null){
            permissionRequestCode+=100 //预留100个空间，让父子fragment的requestCode不相同
            topFragmentRequestPermissions(fragment.parentFragment,needPermissions,requestCode)
        }else{
            fragment.requestPermissions(needPermissions, requestCode)
        }
    }
    //默认的请求时提示
    protected fun onShowPermissionRationaleDefault(requestCode: Int, needPermissions: Array<String>) {
        var needPermissionsDesc = "["
        RequestPermission.permissionsDesc(needPermissions).forEach { p ->
            needPermissionsDesc += ",$p"
        }
        needPermissionsDesc += "]"

        val alertBuilder = AlertDialog.Builder(context)
        alertBuilder.setCancelable(false)
        alertBuilder.setTitle("请求允许权限,否则影响部分功能使用")
        alertBuilder.setMessage("请求${needPermissionsDesc}相关权限,清选择允许")
        alertBuilder.setPositiveButton("知道了") { dialog, which ->
            //子Fragment中使用requestPermissions方法,onRequestPermissionsResult不会回调回来,必须顶级topFragment.RequestPermissions
            topFragmentRequestPermissions(this,needPermissions, requestCode)
            dialog.dismiss()
        }
        alertBuilder.create().show()
    }

    //默认的拒绝时提示
    protected fun onPermissionsDeniedDefault(deniedPermissions: Array<String>, isShowRequestPermissionRationale: Boolean) {
        var deniedPermissionsDesc = "["
        RequestPermission.permissionsDesc(deniedPermissions).forEach { p ->
            deniedPermissionsDesc += ",$p"
        }
        deniedPermissionsDesc += "]"
        val alertBuilder = AlertDialog.Builder(context)
        alertBuilder.setCancelable(false)
        alertBuilder.setTitle("需允许权限,否则影响部分功能使用")
        if (isShowRequestPermissionRationale) {
            alertBuilder.setMessage("刚禁止了${deniedPermissionsDesc}相关权限,请设置为允许")
        } else {
            alertBuilder.setTitle("需允许权限,否则影响部分功能使用")
            alertBuilder.setMessage("以往禁止了${deniedPermissionsDesc}相关权限,请设置为允许")
        }
        alertBuilder.setPositiveButton("去设置") { dialog, which ->
            val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
            intent.data = Uri.parse("package:" + BuildConfig.APPLICATION_ID) // 根据包名打开对应的设置界面
            this.startActivity(intent)
            dialog.dismiss()
        }
        alertBuilder.setNegativeButton("取消") { dialog, which ->
            dialog.dismiss()
        }
        alertBuilder.create().show()
    }

    //给子类使用的,公开方法

    @TargetApi(Build.VERSION_CODES.M)
    protected fun requestPermissionRunAsync(permissions: Array<String>
                                            , onShowPermissionRationale: (requestCode: Int, needPermissions: Array<String>) -> Unit = { r, p -> onShowPermissionRationaleDefault(r, p) }
                                            , onPermissionsDenied: (deniedPermissions: Array<String>, isShowRequestPermissionRationale: Boolean) -> Unit = { p, s -> onPermissionsDeniedDefault(p, s) }
                                            , onPermissionsGranted: () -> Unit) {
        val currentAPIVersion = Build.VERSION.SDK_INT
        if (currentAPIVersion >= android.os.Build.VERSION_CODES.M) {
            //已被禁止的和需要请求的
            val hasDeniedPermissions = mutableListOf<String>()
            val needPermissions = mutableListOf<String>()
            permissions.forEach { permission ->
                if (context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
                    //检查权限申请框是否会显示
                    if (shouldShowRequestPermissionRationale(permission)) {
                        //需要请求的
                        needPermissions.add(permission)
                    } else {
                        //已被禁止的
                        hasDeniedPermissions.add(permission)
                    }

                } else {
                    onPermissionsGranted()
                }
            }

            if (needPermissions.size > 0) {
                //还有权限需要请求,更新请求码
                permissionRequestCode++
                onShowPermissionRationale(permissionRequestCode, needPermissions.toTypedArray())
                val requestPermission = RequestPermission(needPermissions.toTypedArray(), hasDeniedPermissions.toTypedArray(), onPermissionsDenied, onPermissionsGranted)
                //不重复添加 key 是requestCode
                if (!requestPermissionMap.values.contains(requestPermission)) requestPermissionMap.put(permissionRequestCode, requestPermission)
            } else if(hasDeniedPermissions.size>0){
                //全部权限已被禁止
                onPermissionsDenied(hasDeniedPermissions.toTypedArray(), false)
            }
        } else {
            onPermissionsGranted()
        }
    }

    //处理权限请求回调,不允许再继承
    final override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestPermissionMap.containsKey(requestCode)) {
            val deniedPermissions = mutableListOf<String>()
            permissions.forEachIndexed { i, permission ->
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) deniedPermissions.add(permission)
            }
            deniedPermissions.addAll(requestPermissionMap[requestCode]!!.hasDeniedPermissions)
            if (deniedPermissions.size > 0) {
                //有部分拒绝
                requestPermissionMap[requestCode]!!.onPermissionsDenied(deniedPermissions.toTypedArray(), true)
            } else {
                //全部允许
                requestPermissionMap[requestCode]!!.onPermissionsGranted()
            }
            //处理完回调,销毁改对象
            requestPermissionMap.remove(requestCode)
        }else{
            //自己无法处理,尝试让子Fragment处理
            //子Fragment中使用requestPermissions方法,onRequestPermissionsResult不会回调回来,必须顶级topFragment.RequestPermissions
            //追加以下代码,一路透传调用直到有子Fragment能处理
            val fragments = childFragmentManager.fragments
            if (fragments != null) {
                for (f in fragments) {
                    f?.onRequestPermissionsResult(requestCode, permissions, grantResults)
                }
            }
        }
    }





}